/*
 *  Copyright 2025 Collate.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import Document from '@tiptap/extension-document';
import Paragraph from '@tiptap/extension-paragraph';
import Placeholder from '@tiptap/extension-placeholder';
import Table from '@tiptap/extension-table';
import TableCell from '@tiptap/extension-table-cell';
import TableHeader from '@tiptap/extension-table-header';
import TableRow from '@tiptap/extension-table-row';
import TaskItem from '@tiptap/extension-task-item';
import TaskList from '@tiptap/extension-task-list';
import Text from '@tiptap/extension-text';
import { Extensions } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import {
  ExtensionOptions,
  FileType,
} from '../components/BlockEditor/BlockEditor.interface';
import BlockAndDragDrop from '../components/BlockEditor/Extensions/BlockAndDragDrop/BlockAndDragDrop';
import { Callout } from '../components/BlockEditor/Extensions/Callout/Callout';
import DiffView from '../components/BlockEditor/Extensions/diff-view';
import FileNode from '../components/BlockEditor/Extensions/File/FileNode';
import { Focus } from '../components/BlockEditor/Extensions/focus';
import { Hashtag } from '../components/BlockEditor/Extensions/hashtag';
import { hashtagSuggestion } from '../components/BlockEditor/Extensions/hashtag/hashtagSuggestion';
import { LinkExtension } from '../components/BlockEditor/Extensions/link';
import MathEquation from '../components/BlockEditor/Extensions/MathEquation/MathEquation';
import { Mention } from '../components/BlockEditor/Extensions/mention';
import { mentionSuggestion } from '../components/BlockEditor/Extensions/mention/mentionSuggestions';
import slashCommand from '../components/BlockEditor/Extensions/slash-command';
import { getSuggestionItems } from '../components/BlockEditor/Extensions/slash-command/items';
import renderItems from '../components/BlockEditor/Extensions/slash-command/renderItems';
import TextHighlightView from '../components/BlockEditor/Extensions/text-highlight-view';
import { TrailingNode } from '../components/BlockEditor/Extensions/trailing-node';
import { DROP_CURSOR_COLOR } from '../constants/BlockEditor.constants';

/**
 * Base class for BlockEditor extensions configuration
 * This class provides the core extensions for the BlockEditor
 * and allows for extensibility through inheritance
 */
export class BlockEditorExtensionsClassBase {
  /**
   * Get the core extensions for the BlockEditor
   * These are the base extensions that are always included
   */
  protected getCoreExtensions(): Extensions {
    return [
      StarterKit.configure({
        heading: {
          levels: [1, 2, 3],
        },
        bulletList: {
          HTMLAttributes: {
            class: 'om-list-disc',
          },
        },
        orderedList: {
          HTMLAttributes: {
            class: 'om-list-decimal',
          },
        },
        listItem: {
          HTMLAttributes: {
            class: 'om-leading-normal',
          },
        },
        dropcursor: {
          width: 4,
          color: DROP_CURSOR_COLOR,
        },
      }),
      Placeholder.configure({
        showOnlyWhenEditable: true,
        includeChildren: true,
        showOnlyCurrent: false,
        emptyEditorClass: 'is-editor-empty',
        emptyNodeClass: 'is-node-empty',
        placeholder: ({ editor: coreEditor, node }) => {
          if (coreEditor.isDestroyed) {
            return '';
          }
          if (node.type.name === 'heading') {
            return `Heading ${node.attrs.level}`;
          }

          return 'Type "/" for commands...';
        },
      }),
      LinkExtension.configure({
        autolink: false,
        openOnClick: true,
        linkOnPaste: true,
        HTMLAttributes: {
          rel: 'noopener noreferrer nofollow',
          target: '_blank',
        },
        validate: (href) => /^https?:\/\//.test(href),
      }),
      slashCommand.configure({
        slashSuggestion: {
          items: getSuggestionItems,
          render: renderItems,
        },
      }),
      TaskList.configure({
        HTMLAttributes: {
          class: 'om-task-list',
        },
      }),
      TaskItem.configure({
        HTMLAttributes: {
          class: 'om-task-item',
        },
        nested: true,
      }),
      Mention.configure({
        suggestion: mentionSuggestion(),
      }),
      Hashtag.configure({
        suggestion: hashtagSuggestion(),
      }),
    ];
  }

  /**
   * Get additional extensions specific to handlebars functionality
   * Override this in subclasses to add handlebars support
   * @param options - Extension configuration options
   */
  protected getHandlebarsExtensions(): Extensions {
    // Base class returns empty array - no handlebars support by default
    return [];
  }

  /**
   * Get the utility extensions for enhanced editing experience
   */
  protected getUtilityExtensions(): Extensions {
    return [
      DiffView,
      TextHighlightView,
      BlockAndDragDrop,
      Focus.configure({
        mode: 'deepest',
      }),
      Callout,
    ];
  }

  /**
   * Get table-related extensions
   */
  protected getTableExtensions(): Extensions {
    return [
      Table.configure({
        HTMLAttributes: {
          class: 'om-table',
          'data-om-table': 'om-table',
        },
        resizable: true,
      }),
      TableRow.configure({
        HTMLAttributes: {
          class: 'om-table-row',
          'data-om-table-row': 'om-table-row',
        },
      }),
      TableHeader.configure({
        HTMLAttributes: {
          class: 'om-table-header',
          'data-om-table-header': 'om-table-header',
        },
      }),
      TableCell.configure({
        HTMLAttributes: {
          class: 'om-table-cell',
          'data-om-table-cell': 'om-table-cell',
        },
      }),
    ];
  }

  /**
   * Get advanced content extensions
   */
  protected getAdvancedContentExtensions(): Extensions {
    return [
      MathEquation,
      TrailingNode,
      FileNode.configure({
        allowedTypes: [
          FileType.FILE,
          FileType.IMAGE,
          FileType.VIDEO,
          FileType.AUDIO,
        ],
      }),
    ];
  }

  /**
   * Get all extensions combined
   * This is the main method that should be called to get the full extension list
   * @param options - Configuration options for enabling/disabling specific extensions
   */
  public getExtensions(options?: ExtensionOptions): Extensions {
    const {
      enableHandlebars = false,
      coreExtensions = true,
      utilityExtensions = true,
      tableExtensions = true,
      advancedContextExtensions = true,
    } = options ?? {};

    return [
      Document,
      Paragraph,
      Text,
      ...(coreExtensions ? this.getCoreExtensions() : []),
      ...(enableHandlebars ? this.getHandlebarsExtensions() : []),
      ...(utilityExtensions ? this.getUtilityExtensions() : []),
      ...(tableExtensions ? this.getTableExtensions() : []),
      ...(advancedContextExtensions ? this.getAdvancedContentExtensions() : []),
    ];
  }

  /**
   * Hook for content transformation before sending to server
   * Override in subclasses to add custom transformations
   */
  public serializeContentForBackend(html: string): string {
    // Base implementation - no transformation
    return html;
  }

  /**
   * Hook for content transformation when receiving from server
   * Override in subclasses to add custom transformations
   */
  public parseContentFromBackend(html: string): string {
    // Base implementation - no transformation
    return html;
  }
}

const blockEditorExtensionsClassBase = new BlockEditorExtensionsClassBase();

export default blockEditorExtensionsClassBase;
